From e08ecc0000058e476a61af2b503ce34580bd63bc Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Tue, 26 Jul 2005 15:09:43 +0000 Subject: [PATCH] Test and fix acknowedge_watch from returning EINVAL. Also ensure that daemon re-xmits event if they ack wrong thing (otherwise confused clients get stuck, as we will send no more data while awaiting ack). Signed-off-by: Rusty Russel Signed-off-by: Christian Limpach --- tools/xenstore/testsuite/13watch-ack.sh | 22 ++++++++++++++++++++++ tools/xenstore/xenstored_core.c | 2 +- tools/xenstore/xenstored_core.h | 2 +- tools/xenstore/xenstored_watch.c | 15 ++++++++++----- 4 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 tools/xenstore/testsuite/13watch-ack.sh diff --git a/tools/xenstore/testsuite/13watch-ack.sh b/tools/xenstore/testsuite/13watch-ack.sh new file mode 100644 index 0000000000..70a7c6fa3e --- /dev/null +++ b/tools/xenstore/testsuite/13watch-ack.sh @@ -0,0 +1,22 @@ +#! /bin/sh + +# This demonstrates a bug where an xs_acknowledge_watch returns +# EINVAL, because the daemon doesn't track what watch event it sent +# and relies on it being the "first" watch which has an event. +# Watches firing after the first event is sent out will change this. + +# Create three things to watch. +echo mkdir /test | ./xs_test +echo mkdir /test/1 | ./xs_test +echo mkdir /test/2 | ./xs_test +echo mkdir /test/3 | ./xs_test + +# Watch all three, fire event on 2, read watch, fire event on 1 and 3, ack 2. +[ "`echo '1 watch /test/1 token1 0 +1 watch /test/2 token2 0 +1 watch /test/3 token3 0 +2 write /test/2 create contents2 +1 waitwatch +2 write /test/1 create contents1 +2 write /test/3 create contents3 +1 ackwatch token2' | ./xs_test 2>&1`" = "1:/test/2:token2" ] diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index e7c0c11d9d..3eac6407c5 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -1166,7 +1166,7 @@ static void consider_message(struct connection *conn) /* We might get a command while waiting for an ack: this means * the other end discarded it: we will re-transmit. */ if (type != XS_WATCH_ACK) - conn->waiting_for_ack = false; + conn->waiting_for_ack = NULL; /* Careful: process_message may free connection. We detach * "in" beforehand and allocate the new buffer to avoid diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h index 2a5a2b02f5..4aae32e95e 100644 --- a/tools/xenstore/xenstored_core.h +++ b/tools/xenstore/xenstored_core.h @@ -64,7 +64,7 @@ struct connection bool can_write; /* Are we waiting for a watch event ack? */ - bool waiting_for_ack; + struct watch *waiting_for_ack; /* Buffered incoming data. */ struct buffered_data *in; diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c index 6945dd91e0..70bfbaa595 100644 --- a/tools/xenstore/xenstored_watch.c +++ b/tools/xenstore/xenstored_watch.c @@ -102,7 +102,7 @@ void queue_next_event(struct connection *conn) if (conn->waiting_reply) { conn->out = conn->waiting_reply; conn->waiting_reply = NULL; - conn->waiting_for_ack = false; + conn->waiting_for_ack = NULL; return; } @@ -115,7 +115,7 @@ void queue_next_event(struct connection *conn) return; /* If we decide to cancel, we will reset this. */ - conn->waiting_for_ack = true; + conn->waiting_for_ack = event->watches[0]; /* If we deleted /foo and they're watching /foo/bar, that's what we * tell them has changed. */ @@ -348,12 +348,17 @@ bool do_watch_ack(struct connection *conn, const char *token) if (!conn->waiting_for_ack) return send_error(conn, ENOENT); - event = get_first_event(conn); - if (!streq(event->watches[0]->token, token)) + event = list_top(&conn->waiting_for_ack->events, + struct watch_event, list); + assert(event->watches[0] == conn->waiting_for_ack); + if (!streq(conn->waiting_for_ack->token, token)) { + /* They're confused: this will cause us to send event again */ + conn->waiting_for_ack = NULL; return send_error(conn, EINVAL); + } move_event_onwards(event); - conn->waiting_for_ack = false; + conn->waiting_for_ack = NULL; return send_ack(conn, XS_WATCH_ACK); } -- 2.30.2